package com.enbatis.mybatisplugs.commons.sql;

import com.enbatis.mybatisplugs.commons.utils.BaseUtil;
import com.enbatis.mybatisplugs.commons.utils.LineHumpUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.util.*;

public class Wrapper<T> {

    private static final String MYBATIS_PLUGS_TOKEN = "#{%s.paramNameValuePairs.%s}";

    private final Map<String, Object> eqSql = new HashMap<>();

    private final Map<String, Object> neSql = new HashMap<>();


    private final Map<String, Collection<?>> inSqlMap = new HashMap<>();


    private final Map<String, Object> likeSqlMap = new HashMap<>();

    public Wrapper(T entity) {
        this.entity = entity;
        this.initEntityQuery(entity);
    }

    public void setObj(T entity){
        this.entity = entity;
        this.initEntityQuery(entity);
    }


    public Wrapper() {
    }

    protected  void  initEntityQuery(T entity){
        Class userCla = entity.getClass();

        try {
            Field[] fs = userCla.getDeclaredFields ();
            for ( int i = 0 ; i < fs. length ; i++){
                Field f = fs[i];
                f.setAccessible( true ); //
                Object val = f.get(entity); //
                if (null!=val){
                    eqSql.put(LineHumpUtil.humpToLine(f.getName()),val);
                }

            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    private  T entity;


    protected String sqlSelect = null;

    protected String sqlEq = "";

    protected String sqlNq = "";

    protected String sqlNotNull = "";

    protected String sqlNull = "";

    private  String sql;

    private  String sqlLike;


    private  String wholeQuerySql;



    private  StringBuilder orderBy=null;

    public String getSqlNotNull() {
        return sqlNotNull;
    }

    public void setSqlNotNull(String sqlNotNull) {
        this.sqlNotNull = sqlNotNull;
    }

    public String getSqlNull() {
        return sqlNull;
    }

    public void setSqlNull(String sqlNull) {
        this.sqlNull = sqlNull;
    }

    public T getEntity() {
        return entity;
    }

    public void setEntity(T entity) {
        this.entity = entity;
    }

    public String getSql() {
        return sql;
    }

    public void setSql(String sql) {
        this.sql = sql;
    }

    public String getSqlSelect() {
        return sqlSelect;
    }


    public Wrapper<T> setSqlSelect(String... columns) {
        StringBuilder builder = new StringBuilder();
        for (String column : columns) {
            if (StringUtils.isNotEmpty(column)) {
                if (builder.length() > 0) {
                    builder.append(",");
                }
                builder.append(column);
            }
        }
        this.sqlSelect = builder.toString();
        return this;
    }

    public Wrapper<T> eq(String columns,Object object) {
        eqSql.put(columns,object);
        return this;
    }


    public Wrapper<T> in(String columns, Collection<?> objectList) {
        inSqlMap.put(columns,objectList);
        return this;
    }


    public Wrapper<T> in(String columns, Object[] objectList) {
        inSqlMap.put(columns,Arrays.asList(objectList));
        return this;
    }

    public Wrapper<T> ne(String columns,Object object) {
        neSql.put(columns,object);
        return this;
    }


    public Wrapper<T> like(String column,String object) {
        likeSqlMap.put(column,object);
        return this;
    }


    public Wrapper<T> orderBy(String column,boolean asc) {

         if (null==this.orderBy){
             orderBy=new StringBuilder();

             orderBy.append(" "+column+" "+(asc?"ASC":"DESC"));
         }else{
             orderBy.append(" , ").append(column).append(asc?"ASC":"DESC");
         }


        return this;
    }


    public Wrapper<T> notNull(String... columns) {

        if (ArrayUtils.isEmpty(columns)){
            return this;
        }

        StringBuilder builder = new StringBuilder();
        for (String c:columns) {
            builder.append(" AND  "+c+" IS NOT NULL ");
        }
        this.sqlNotNull=builder.toString();
        return this;
    }


    public Wrapper<T> isNull(String... columns) {

        if (ArrayUtils.isEmpty(columns)){
            return this;
        }

        StringBuilder builder = new StringBuilder();
        for (String c:columns) {
            builder.append(" AND  "+c+" IS  NULL ");
        }
        this.sqlNull=builder.toString();
        return this;
    }


    public Map<String, Object> getEqSql() {
        return eqSql;
    }

    public String getSqlEq() {

        StringBuilder sb=new StringBuilder();
        for (Map.Entry<String,Object> entry:eqSql.entrySet()) {

            sb.append(sqlSplitJoint(entry.getKey(),entry.getValue()));
        }
        this.sqlEq=sb.toString();
        return this.sqlEq;
    }



    public String getSqlNq() {

        StringBuilder sb=new StringBuilder();
        for (Map.Entry<String,Object> entry:neSql.entrySet()) {
            sb.append(sqlSplitNotJoint(entry.getKey(),entry.getValue()));
        }
        this.sqlNq=sb.toString();
        return this.sqlNq;
    }



    public String getSqlLike() {

        StringBuilder sb=new StringBuilder();
        for (Map.Entry<String,Object> entry:likeSqlMap.entrySet()) {
            sb.append(" AND "+entry.getKey()+" LIKE CONCAT('%','"+entry.getValue()+"','%')");
        }
        this.sqlLike=sb.toString();
        return this.sqlLike;
    }



    public String  sqlSplitJoint(String param,Object object){
         if (object instanceof  Integer){
             return  " AND "+ param+" = "+object;
         }else if (object instanceof  String){
             if (!"".equalsIgnoreCase((String) object)){
                 return  " AND "+ param+" = '"+object+"'";
             }
             return "";

         }else if (object instanceof Date){
             return  " AND "+ param+" = '"+object+"'";
         }else{
             return  " AND "+ param+" = "+object;
         }
    }



    public String  sqlSplitNotJoint(String param,Object object){
        if (object instanceof  Integer){
            return  " AND "+ param+" != "+object;
        }else if (object instanceof  String){
            return  " AND "+ param+" != '"+object+"'";
        }else if (object instanceof Date){
            return  " AND "+ param+" != '"+object+"'";
        }else{
            return  " AND "+ param+" != "+object;
        }
    }



    public String getOrderBy(){

        if (null==orderBy){
            return null;
        }
        return  orderBy.toString();
    }


    public String getWholeQuerySql() {
      StringBuilder sb=new StringBuilder();
      String getSqlEq= this.getSqlEq();
      String getSqlNq= this.getSqlNq();
      String getSqlNotNull= this.sqlNotNull;
      String getSqlNull= this.sqlNull;
        String  getSqlLike= this.getSqlLike();

      if (StringUtils.isNotBlank(getSqlEq)){
          sb.append(getSqlEq).append(" ");
      }
     if (StringUtils.isNotBlank(getSqlNq)){
        sb.append(getSqlNq).append(" ");
      }
     if (StringUtils.isNotBlank(getSqlNotNull)){
        sb.append(getSqlNotNull).append(" ");
      }
     if (StringUtils.isNotBlank(getSqlNull)){
        sb.append(getSqlNull).append(" ");
     }
        if (StringUtils.isNotBlank(getSqlLike)){
            sb.append(getSqlLike).append(" ");
        }

        if (null!=inSqlMap){
          Set<String> set=  inSqlMap.keySet();
            for (String s:set) {
               Collection<?> inList= inSqlMap.get(s);
               String insql=  BaseUtil.join(inList);

                sb.append(" AND  "+s+" IN (  "+insql+" ) ");
            }
        }


     this.wholeQuerySql=sb.toString();
     return this.wholeQuerySql;
    }



}
